#encoding=utf8

from google.appengine.ext import db
import logging
import random
import skilldata
import monsterdata
import datetime


scns = [
		{
			'name': 'newbird',
			'title': '新手剧本',
			'monster': [ [2000, 2000, 2000], [ 2001 for i in range(0,12)], [2003, 2003, 2003, 2002], 'epic', [2004], [2005 for i in range(0,6)], [2006]  ],
			},

		{
			'name': 'sandoftime',
			'title': '时之沙',
			'monster': [ [3000,3000,3000], [3001 for i in range(0,6)], [3001 for i in range(0,6)], [3001 for i in range(0,6)], [3001 for i in range(0,6)], [3001 for i in range(0,6)], [38], 'epic', [3002], [3003, 3003], [3004, 3004, 3004], [3005] ],
			},

		{
			'name': 'feyforest',
			'title': '疯狂森林',
			'monster': [ [11 for i in range(0,5)], [17], [24, 24, 24, 24], 'epic', [20 for i in range(0,6)], [33] ],
			},

		{
			'name': 'icecave',
			'title': '寒冰洞穴',
			'monster': [ [38], [14,14], [18, 18, 18], 'epic', [21,21,21,21], [32] ],
			},

		{
			'name': 'dan',
			'title': '盗贼城',
			'monster': [ 'epic', [41], [12,12,12,12], [36], [19,19], [42], [34] ],
			},

		{
			'name': 'depths',
			'title': '矮人矿坑',
			'monster': [ [11 for i in range(0,5)], [38], 'epic', [13 for i in range(0,6)], [28,28,28,28], [35] ],
			},

		{
			'name': 'arcane',
			'title': '秘银塔',
			'monster': [ [10 for i in range(0,6)],  [16,16], [23], 'epic', [22], [25,25,25] ],
			},
]


scnmap = dict()
for scn in scns:
	scnmap[scn.get('name')] = scn


jobs = [
		{
			'type': 'fighter',
			'name': 'fighter',
			'title': '战士',
			'hp': 6,
			'epic': 'flame',
			},

		{
			'type': 'fighter',
			'name': 'paladin',
			'title': '圣骑士',
			'hp': 6,
			'epic': 'divinity',
			},

		{
			'type': 'rogue',
			'name': 'rogue',
			'title': '游侠',
			'hp': 4,
			'desc': '每回合只能攻击1个目标',
			'epic': 'subtlety',
			},

		{
			'type': 'rogue',
			'name': 'ranger',
			'title': '巡林客',
			'hp': 4,
			'hide': True,
			},

		{
				'type': 'wizard',
				'name': 'wizard',
				'title': '术士',
				'hp': 1,
				'epic': 'gandr',
			},

		{
				'type': 'wizard',
				'name': 'sorcerer',
				'title': '法师',
				'hp': 1,
				'hide': True,
				},	

		{
				'type': 'cleric',
				'name': 'cleric',
				'title': '牧师',
				'hp': 3,
				'epic': 'holysymbol',
				},

		{
				'type': 'cleric',
				'name': 'druid',
				'title': '德鲁伊',
				'hp': 3,
				'epic': 'entangling',
				},
]

jobmap = dict()
for job in jobs:
	job['skills'] = list()
	jobmap[job.get('name')] = job

for skill in skilldata.skills:
	job = jobmap.get(skill.get('job'))
	job['skills'].append(skill)


def rollPhase(rh, player):
	player['exile'] = 0
	player['weak'] = 0
	if player['rollcnt']==0:
		player['turn'] = player['turn'] + 1

	#取出本轮保留骰子，若全部保留就开始使用技能
	old_dices = player.get('dice')
	sel_dice = list()
	for i in range(0,player.get('dice_cnt')):
		on = rh.request.get('d%d' % i)
		if on:
			sel_dice.append(old_dices[i])
	cnt = player.get('dice_cnt') - len(sel_dice)
	if cnt==0:
		player['phase'] = 'skill'
		return {'dices': sel_dice}

	#摇骰子
	player['rollcnt'] = player['rollcnt'] + 1
	if player['rollcnt']>=3:
		player['phase'] = 'skill'
	dices = old_dices[:]
	while dices==old_dices:
		dices = [random.randint(1,6) for i in range(0,cnt)] + sel_dice
		dices.sort()
	player['dice'] = dices
	player['dice_old'] = dices[:]
	return {'dices': dices, 'can_sel': player['rollcnt']<3}


def getAliveMemberJob(player):
	team = player.get('team')
	rst = list()
	for mem in team:
		if mem.get('st') > 0:
			rst.append(mem.get('data').get('name'))
	return rst				


def useSelectSkill(rh, player):
	skillkey = rh.request.get('skill')
	if skillkey=='':
		return
	try:
		skillkey = eval(skillkey)
	except:
		return
	skill = skilldata.skillmap.get(skillkey.get('name'))
	if not skill:
		return
	if not skill.get('job') in getAliveMemberJob(player):
		return
	combo = skillkey.get('combo')
	combos = skill.get('checker')(player)
	if not combo in combos:
		return
	#消耗玩家的骰子资源
	dices = player.get('dice')
	if combo!=[0]:
		for d in combo:
			dices.remove(d)
	player['dice'] = dices
	#计算数值
	pt = skill.get('eff1')(combo, player)
	if pt=='*':
		skill.get('eff2')(combo, rh, player)
	elif pt>0:
		members = player.get('team')
		for member in members:
			if pt<=0:
				return
			select = rh.request.get(member.get('data').get('name'))
			try:
				select = int(select)
				if select>pt:
					select=pt
			except:
				select = 0
			if select>0:
				hp = member.get('hp')
				if hp>0 and member.get('st')>0:
					member['hp'] = hp + select
					pt = pt - select
				if hp==0 and member.get('st')==0:
					#圣骑士加血复活
					if skill.get('name')=='lay' and player.get('divinity'):
						member['hp'] = hp + select
						member['st'] = 1
						pt = pt - select
				if member.get('hp')>member.get('data').get('hp'):
					pt = pt + member.get('hp') - member.get('data').get('hp')
					member['hp'] = member.get('data').get('hp')
	elif pt<0:
		pt = abs(pt)
		enemys = player.get('enemy')
		idx = 0
		for enemy in enemys:
			if pt<=0:
				return
			select = rh.request.get('hurt_%d' % idx)
			idx = idx + 1
			try:
				select = int(select)
				if select>pt:
					select = pt
			except:
				select = 0
			if select>0:
				hit = True
				#盗贼一次攻击一个目标
				if skill.get('job')=='rogue':
					rogue_target = player.get('rogue_target')
					if rogue_target and rogue_target!=enemy:
						hit = False
					else:
						player['rogue_target'] = enemy
				#战士冲锋计次		
				if skill.get('name')=='charge':
					player['charge'] = player['charge'] + 1
				hp = enemy.get('hp')
				if hp>0 and hit:
					enemy['hp'] = hp - select
					pt = pt - select
					enemy['round_hurt'] = enemy.get('round_hurt') + select
				if enemy.get('hp')<0:
					enemy['hp'] = 0


def calcEnemyHit(player):
	if player.get('entangling'):
		player['entangling'] = False
		return
	enemys = player.get('enemy')
	for enemy in enemys:
		if enemy.get('hp')>0:
			dices = enemy.get('data').get('dice_fn')(enemy.get('hp'), player)
			for h in enemy.get('data').get('hit'):
				player['enemy_hit'] = player['enemy_hit'] + dices.count(h)
			eff_fn = enemy.get('data').get('eff_fn')
			if eff_fn:
				eff_fn(dices, player, enemy)


def isLevelClear(player):
	for enemy in player.get('enemy'):
		if enemy.get('hp')>0:
			return False
	return True	


def skillPhase(rh, player):
	if isLevelClear(player):
		player['enemy'] = list()
		Game.loadNextLevel(player)
		return {'next_phase': '进入下一层'}
	useSelectSkill(rh, player)
	# 生成技能
	skill_list = list()
	team = getAliveMemberJob(player)
	for s in skilldata.skills:
		if s.get('job') in team:
			combos = s.get('checker')(player)
			for combo in combos:
				key = {'combo': combo, 'name': s.get('name')}
				eff = s.get('eff1')
				skill_list.append({'combo': combo, 'data': s, 'key': str(key), 'hit': eff(combo, player)})
	if len(skill_list)==0:
		if isLevelClear(player):
			player['enemy'] = list()
			Game.loadNextLevel(player)
			return {'next_phase': '进入下一层'}
		else:
			calcEnemyHit(player)
			player['phase'] = 'enemy'
			return {'next_phase': '接下来是怪物攻击'}
	return {'dices': player.get('dice'), 'skill_list': skill_list, 
			'ehoptions': monsterdata.hurt_option, 'mcoptions': monsterdata.cure_option}


def enemyPhase(rh, player):	
	if len(getAliveMemberJob(player))==0:
		player['phase'] = 'fin'
		return dict()
	hit = player.get('enemy_hit')
	for member in player.get('team'):
		select = rh.request.get(member.get('data').get('name'))
		if select=='exile':
			if member.get('st')>0 and player.get('exile')>0:
				player['exile'] = player.get('exile') - 1
				member['hp'] = 0
				member['st'] = -1
		try:
			select = int(select)
		except:
			select = 0
		if select>0 and member.get('st')>0:
			if select > member.get('hp'):
				select = member.get('hp')
			if select > hit:
				select = hit
			member['hp'] = member.get('hp') - select
			hit = hit - select
			if member.get('hp')<=0:
				member['hp'] = 0
				member['st'] = 0
	player['enemy_hit'] = hit			
	if hit<=0 and player.get('exile')<=0 and player.get('kill')<=0:
		player['phase'] = 'roll'
		Game.resetRound(player)
		if player.get('fast_next'):
			Game.loadNextLevel(player)
			del player['fast_next']
		return dict()
	return {'mcoptions': monsterdata.cure_option}


def epicPhase(rh, player):
	job = rh.request.get('epic')
	if job in getAliveMemberJob(player):
		job = jobmap.get(job)
		player[job.get('epic')] = True
		Game.loadNextLevel(player)
		return {'next_phase': '进入下一层'}
	return dict()


def finPhase(rh, player):
	team = getAliveMemberJob(player)
	tip_txt = ''
	key = player.get('user')
	if len(team)==0:
		game.RemovePlayer(player)
		tip_txt = '您死翘翘了....'
	scn = player.get('scn')
	if len(team)>0 and player.get('level')>=len(scn.get('monster')):
		# 存盘
		user = db.get(key)
		score = 10000 / player.get('turn')
		found = False
		for r in user.ranks:
			rdata = eval(r)
			if rdata.get('scn')==scn.get('title'):
				found = r
		if found and score>rdata.get('score'):			
			user.ranks.remove(found)
			user.ranks.append(str({'scn': scn.get('title'), 'score': score}))
		elif not found:
			user.ranks.append(str({'scn': scn.get('title'), 'score': score}))
		user.put()	
		game.RemovePlayer(player)
		tip_txt = '您完成了伟大的冒险,诗人将传诵您的战斗英姿'
	return {'user_id': key, 'tip_txt': tip_txt}


phases = [
		{
			'name': 'roll',
			'html': 'roll.html',
			'handler': rollPhase,
			},

		{
			'name': 'skill',
			'html': 'skill.html',
			'handler': skillPhase,
			},

		{
			'name': 'enemy',
			'html': 'onfire.html',
			'handler': enemyPhase,
			},

		{
			'name': 'epic',
			'html': 'epic.html',
			'handler': epicPhase,
			},

		{
			'name': 'fin',
			'html': 'fin.html',
			'handler': finPhase,
			},
		]

phasemap = dict()
for phase in phases:
	phasemap[phase.get('name')] = phase


class Game():
	def __init__(self):
		self.players = dict()
		self.nextid = 1

	@staticmethod
	def createTeam(jobs):
		rst = list()
		for job in jobs:
			rst.append({'data': job, 'hp': job.get('hp'), 'st': 1})
		return rst	

	@staticmethod
	def resetRound(player):
		for e in player.get('enemy'):
			e['round_hurt'] = 0
		player['charge'] = 0
		player['rogue_target'] = None
		player['rollcnt'] = 0
		player['dice'] = list()
		player['dec_enemy_dice'] = 0

	@staticmethod
	def loadNextLevel(player):
		Game.resetRound(player)
		if player.has_key('entangling'):
			player['entangling'] = True
		scn = player.get('scn')
		monsterlist = scn.get('monster')
		level = player.get('level')
		if level<len(monsterlist):
			player['enemy_hit'] = 0
			if player.get('poison'):
				player['enemy_hit'] = player.get('enemy_hit') + 1
			monsterIDs = monsterlist[level]
			player['level'] = level + 1
			if monsterIDs=='epic':
				player['phase'] = 'epic'
				return
			pm = player.get('enemy')
			for monsterid in monsterIDs:
				monster = monsterdata.monstermap.get(monsterid)
				encounter = True
				if monster.get('trap') and 'rogue' in getAliveMemberJob(player):
					if [1,2,3].count(random.randint(1,6))==1: #盗贼的躲避陷阱技能
						encounter = False
				if encounter:
					pm.append({'data': monster, 'hp': monster.get('hp'), 'round_hurt': 0})
				else:
					pm.append({'data': monster, 'hp': 0, 'round_hurt': 0})
			player['enemy'] = pm	
			player['phase'] = 'roll'
		else:
			player['phase'] = 'fin'

	def Start(self, key, scn, fighter, rogue, wizard, cleric):
		self.players[key] = player = {
				'user': key,
				'gid': self.nextid,
				'turn': 0,
				'dice': list(),
				'phase': 'roll',
				'rollcnt': 0,
				'dice_cnt': 6,

				'scn': scn,
				'level': 0,
				'enemy': list(),
				'team': Game.createTeam([fighter, rogue, wizard, cleric]),
				}
		oid = self.nextid
		self.nextid = oid + 1
		Game.loadNextLevel(player)
		return oid

	def Play(self, rh):
		key = rh.request.get('id')
		player = self.players.get(key)
		if not player:
			return
		gid = rh.request.get('gid')
		if not int(gid)==player.get('gid'):
			return
		player['last_time'] = datetime.datetime.now()
		phase = phasemap.get(player.get('phase'))
		param = phase.get('handler')(rh, player)
		param['html'] = phase.get('html')
		param['player'] = player
		return param

	def GetPlayer(self, key):
		return self.players.get(key)

	def RemovePlayer(self, player):
		del self.players[player.get('user')]

	def CleanTimeoutPlayers(self):
		keys = list()
		oldcnt = len(self.players)
		curtime = datetime.datetime.now()
		for player in self.players.values():
			lasttime = player.get('last_time')
			if (curtime - lasttime).seconds > 60*30:
				keys.append(player.get('user'))

		for k in keys:
			del self.players[k]
		return (oldcnt, len(self.players))	


game = Game()	



